﻿/**
 * @file XImageListView.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-12-20
 * @version : 1.0.0.0
 * @brief   : 图片列表显示的视图部件。
 */

#include "xtypes.h"
#include "XImageListView.h"

#include <QPainter>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QDir>

////////////////////////////////////////////////////////////////////////////////
// XImageItemDelegate

//====================================================================

//
// XImageItemDelegate : constructor/destructor
//

XImageItemDelegate::XImageItemDelegate(QObject *parent)
    : QItemDelegate(parent)
{

}

XImageItemDelegate::~XImageItemDelegate(void)
{

}

//====================================================================

//
// XImageItemDelegate : overrides
//

void XImageItemDelegate::paint(
        QPainter *painter,
        const QStyleOptionViewItem &option,
        const QModelIndex &index) const
{
    //======================================

    QItemDelegate::paint(painter, option, index);

    //======================================

    if (0 != index.column())
    {
        return;
    }

    XImageListView * listView = static_cast< XImageListView * >(parent());

    bool selected = (index.row() == listView->currentIndex().row()) && listView->hasFocus();

    QColor clrText = painter->pen().color();
    if (selected)
    {
        painter->setPen(Qt::white);
    }

    painter->drawText(
                option.rect,
                Qt::AlignCenter,
                QString("%1").arg(index.row() + 1));

    if (selected)
    {
        painter->setPen(clrText);
    }

    //======================================
}

QSize XImageItemDelegate::sizeHint(
        const QStyleOptionViewItem &option,
        const QModelIndex &index) const
{
    QSize size = QItemDelegate::sizeHint(option, index);
    size.setHeight(size.height() + 8);
    return size;
}

////////////////////////////////////////////////////////////////////////////////
// XImageListView

//====================================================================

// 
// XImageListView : constructor/destructor
// 

XImageListView::XImageListView(QWidget *parent)
    : QTreeView(parent)
{
    //======================================
    // 设置列表的表头，以及 列表行 的绘制托管对象。

    m_itemModel = new QStandardItemModel(0, 3, this);
    m_itemModel->setHeaderData(0, Qt::Horizontal, QObject::tr("序号"), Qt::DisplayRole);
    m_itemModel->setHeaderData(1, Qt::Horizontal, QObject::tr("路径"), Qt::DisplayRole);
    m_itemModel->setHeaderData(2, Qt::Horizontal, QObject::tr("宽高"), Qt::DisplayRole);

    this->setModel(m_itemModel);

    XImageItemDelegate * xItemDelegate = new XImageItemDelegate(this);
    this->setItemDelegate(xItemDelegate);

    //======================================
    // 设置列表样式

    this->setSelectionMode(QAbstractItemView::SingleSelection);
    this->setSelectionBehavior(QAbstractItemView::SelectRows);

    this->setAcceptDrops(true);
    this->setDropIndicatorShown(true);
    this->setDragEnabled(true);
    this->setDragDropOverwriteMode(true);
    this->setDragDropMode(QTreeView::DragDrop);
    this->setDefaultDropAction(Qt::IgnoreAction);

    //======================================
    // 连接 信号 与 槽

    connect(this,
            SIGNAL(requireSizeInfo(int)),
            this,
            SLOT(on_loadSizeInfo(int)),
            Qt::ConnectionType::QueuedConnection);

    //======================================
}

XImageListView::~XImageListView(void)
{

}

//====================================================================

// 
// XImageListView : overrides of event
// 

void XImageListView::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat(tr("text/uri-list")))
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
    else
    {
        QTreeView::dragEnterEvent(event);
    }
}

void XImageListView::dragMoveEvent(QDragMoveEvent *event)
{
    setDropIndicatorShown(true);

    if ((this != event->source()) && event->mimeData()->hasFormat(tr("text/uri-list")))
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
    else
    {
        QTreeView::dragMoveEvent(event);
    }
}

void XImageListView::dropEvent(QDropEvent *event)
{
    if ((this != event->source()) && event->mimeData()->hasFormat(tr("text/uri-list")))
    {
        do
        {
            QList< QUrl > urls = event->mimeData()->urls();
            if (urls.empty())
                break;

            QStringList strImages;
            for (QList< QUrl >::iterator
                 iter  = urls.begin();
                 iter != urls.end();
                 ++iter)
            {
                QString strImage = iter->toLocalFile();
                if ((0 == strImage.right(3).compare(tr("jpg" ), Qt::CaseInsensitive)) ||
                    (0 == strImage.right(4).compare(tr("jpeg"), Qt::CaseInsensitive)))
                {
                    strImages.append(strImage);
                }
            }

            if (strImages.empty())
                break;
            strImages.sort(Qt::CaseInsensitive);
            if (importImages(strImages) > 0)
                this->scrollToBottom();
        } while (0);
    }
    else
    {
        do
        {
            //======================================

            if (this != event->source())
            {
                break;
            }

            //======================================

            QStringList strFormats = event->mimeData()->formats();
            if (strFormats.isEmpty())
                break;

            int srcRow = -1;
            int dstRow = -1;

            QByteArray byteArr = event->mimeData()->data(strFormats[0]);
            QDataStream dataStream(&byteArr, QIODevice::ReadOnly);
            dataStream >> srcRow;

            dstRow = this->indexAt(event->pos()).row();
            if (-1 == dstRow)
            {
                dstRow = rowCount() - 1;
            }

            if (srcRow == dstRow)
                break;

            //======================================

            QList< QStandardItem * > itemList;
            itemList.append(new QStandardItem(m_itemModel->item(srcRow, 0)->text()));
            itemList.append(new QStandardItem(m_itemModel->item(srcRow, 1)->text()));
            itemList.append(new QStandardItem(m_itemModel->item(srcRow, 2)->text()));

            m_itemModel->removeRow(srcRow);
            m_itemModel->insertRow(dstRow, itemList);
            this->setCurrentIndex(m_itemModel->index(dstRow, 0));

            //======================================
        } while (0);
    }

    setDropIndicatorShown(false);
    event->ignore();
}

//====================================================================

//
// XImageListView : public interfaces
//

/**********************************************************/
/**
 * @brief 当前列表的行数。
 */
int XImageListView::rowCount(void) const
{
    return model()->rowCount();
}

/**********************************************************/
/**
 * @brief 从指定文件夹导入各个 JPEG 图片文件路径信息，并显示到列表中。
 */
int XImageListView::importFromDir(const QString & strDir)
{
    QDir dir(strDir,
             tr("*.jpg;*.jpeg"),
             QDir::Name | QDir::IgnoreCase,
             QDir::Files | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot);

    QString strPath = strDir;
    if ((strDir.right(1) != tr("/" )) ||
        (strDir.right(1) != tr("\\")))
    {
        strPath.append('/');
    }

    QStringList strNames = dir.entryList();
    for (QStringList::iterator
         iter = strNames.begin();
         iter != strNames.end();
         ++iter)
    {
        QList< QStandardItem * > itemList;
        itemList.append(new QStandardItem(tr("")));
        itemList.append(new QStandardItem(strPath + *iter));
        itemList.append(new QStandardItem(tr("")));

        m_itemModel->appendRow(itemList);

        emit requireSizeInfo(m_itemModel->rowCount() - 1);
    }

    return strNames.size();
}

/**********************************************************/
/**
 * @brief 导入多个 JPEG 图片文件路径信息，并显示到列表中。
 */
int XImageListView::importImages(const QStringList & strImageFiles)
{
    int iter = 0;

    for (; iter < strImageFiles.size(); ++iter)
    {
        QList< QStandardItem * > itemList;
        itemList.append(new QStandardItem(tr("")));
        itemList.append(new QStandardItem(strImageFiles.at(iter)));
        itemList.append(new QStandardItem(tr("")));

        m_itemModel->appendRow(itemList);

        emit requireSizeInfo(m_itemModel->rowCount() - 1);
    }

    return iter;
}

/**********************************************************/
/**
 * @brief 移除列表行。
 */
bool XImageListView::remove(int row)
{
    QStandardItemModel * model =
        dynamic_cast< QStandardItemModel * >(this->model());

    return model->removeRow(row);
}

/**********************************************************/
/**
 * @brief 清空列表。
 */
void XImageListView::cleanup(void)
{
    m_itemModel->removeRows(0, m_itemModel->rowCount());
}

/**********************************************************/
/**
 * @brief 获取指定行对应的图片文件路径信息。
 */
QString XImageListView::getImagePath(int row) const
{
    QStandardItem * item = m_itemModel->item(row, 1);
    return (nullptr != item) ? item->text() : tr("");
}

/**********************************************************/
/**
 * @brief 读取整个列表的图片信息。
 */
int XImageListView::queryImageList(XImageInfoList & xInfoList)
{
    int nums  = 0;
    int count = m_itemModel->rowCount();

    for (int row = 0; row < count; ++row)
    {
        QStandardItem * itemPath = m_itemModel->item(row, 1);
        QStandardItem * itemSize = m_itemModel->item(row, 2);
        if ((nullptr == itemPath) || (nullptr == itemSize))
        {
            continue;
        }

        std::string xstr_size = itemSize->text().toStdString();
        x_int32_t xit_w = 0;
        x_int32_t xit_h = 0;
        sscanf(xstr_size.c_str(), " %d x %d ", &xit_w, &xit_h);

        xInfoList.push_back(XImageInfo(itemPath->text(), QSize(xit_w, xit_h)));

        nums += 1;
    }

    return nums;
}

//====================================================================

//
// XImageListView : slots
//

/**********************************************************/
/**
 * @brief 信号槽：加载指定行对应的图片尺寸信息，显示到列表中。
 */
void XImageListView::on_loadSizeInfo(int row)
{
    QStandardItem * itemSize = m_itemModel->item(row, 2);
    if ((nullptr == itemSize) || (!itemSize->text().isEmpty()))
    {
        return;
    }

    QStandardItem * itemPath = m_itemModel->item(row, 1);
    if (nullptr == itemPath)
    {
        return;
    }

    std::string xstr_path = itemPath->text().toLocal8Bit().data();
    m_jdecoder.config_src(
                JCTRL_MODE_FILE,
                static_cast< j_handle_t >(const_cast< char * >(xstr_path.c_str())),
                0);

    jpeg_info_t jinfo = { 0, 0, 0, 0 };
    if (JDEC_ERR_OK == m_jdecoder.src_info(&jinfo))
    {
        itemSize->setText(
                QString(tr(" %1 x %2 "))
                    .arg(jinfo.jit_width)
                    .arg(jinfo.jit_height));
    }
}
